package app.util.image.action
{
	import app.util.*;
	
	import flash.display.*;
	import flash.geom.*;
	
	public class RotateAction extends AbstractAction
	{
		private var originalAng:Number;
		private var angle:Number;
		
		public function setAngle(ang:Number):RotateAction
		{
			//Parameter angleOrginal is by 'degree'
			//Constrain the angle value to [0, 2*PI)
			this.originalAng = ang;
			this.angle = ang / 180 * Math.PI;
			var p2:Number = Math.PI * 2;
			while(angle < 0)
			{
				angle += p2;	
			}
			
			while(angle >= p2)
			{
				angle -= p2;
			}
			
			return this;			
		}
		
		public override function getDescription():String
		{
			return "Rotate " + this.originalAng;
		}
		
		public override function getActionedBitmapData():BitmapData
		{
			var m:Matrix = new Matrix();
			var oldBmp:BitmapData = Mediator.getCurrentBitmapData();
			var newW:int, newH:int;		
			var modAngle:Number;
			var fillColor:uint = 0x0;
			
			m.rotate(angle);
			
			if(angle <= Math.PI / 2)
			{
				newW = Math.abs(oldBmp.height * Math.sin(angle) + oldBmp.width * Math.cos(angle));
				newH = Math.abs(oldBmp.height * Math.cos(angle) + oldBmp.width * Math.sin(angle));
				m.translate(oldBmp.height * Math.sin(angle), 0);	
			}
			else if(angle <= Math.PI)
			{
				modAngle = angle - Math.PI / 2;
				newW = Math.abs(oldBmp.height * Math.cos(modAngle) + oldBmp.width * Math.sin(modAngle));
				newH = Math.abs(oldBmp.height * Math.sin(modAngle) + oldBmp.width * Math.cos(modAngle));
				m.translate(newW, oldBmp.height * Math.sin(modAngle));	 
			}
			else if(angle <= Math.PI * 3 / 2)
			{
				modAngle = angle - Math.PI;
				newW = Math.abs(oldBmp.height * Math.sin(modAngle) + oldBmp.width * Math.cos(modAngle));
				newH = Math.abs(oldBmp.height * Math.cos(modAngle) + oldBmp.width * Math.sin(modAngle));
				m.translate(oldBmp.width * Math.cos(modAngle), newH);				
			}
			else 
			{
				modAngle = angle - Math.PI * 3 / 2;
				newW = Math.abs(oldBmp.height * Math.cos(modAngle) + oldBmp.width * Math.sin(modAngle));
				newH = Math.abs(oldBmp.height * Math.sin(modAngle) + oldBmp.width * Math.cos(modAngle));
				m.translate(0, oldBmp.width * Math.cos(modAngle));		
			}
			
			var rotated:BitmapData = new BitmapData(
			  		newW, newH, true, fillColor);
			rotated.draw(oldBmp, m);
			
			rotated = this.doTrim(rotated, fillColor);	
			return rotated;
		}	
		
		private function doTrim(d:BitmapData, trimColor:uint):BitmapData
		{
			//Remove the lines and cols all of trimColor.
			var w:int = d.width, h:int = d.height;			
			var x0:int = 0, x1:int = w - 1;
			var y0:int = 0, y1:int = h - 1;
			var i:int, j:int;
			var color:uint;
			
			//Do line trim, and find x
			for(i = 0; i < w; i++)
			{
				for(j = 0; j < h; j++)
				{
					color = d.getPixel32(i, j);			
					if(color != trimColor)
					{
						break;
					}

				}
				if(j == h)
				{
					if(x0 == i - 1)
					{
						x0 = i;	
					}
					else if(i != 0)
					{
						x1 = i;	
						break;
					}
				}
			}
			
			//Do column trim, and find y
			for(i = 0; i < h; i++)
			{
				for(j = 0; j < w; j++)
				{
					color = d.getPixel32(j, i);
					if(color != trimColor)
					{
						break;
					} 
				}
				if(j == w)
				{
					if(y0 == i - 1)
					{
						y0 = i;	
					}
					else if(i != 0)
					{
						y1 = i;	
						break;
					}
				}
			}			
			var trimed:BitmapData = new BitmapData(x1 - x0 + 1, y1 - y0 + 1, true, trimColor);
			trimed.copyPixels(d, new Rectangle(x0, y0, x1 - x0 + 1, y1 - y0 + 1), new Point(0, 0));
			return trimed;
		}		
	}
}